#pragma once
// ==================包含头文件====================
#include "hal/gpio.hpp"
#include "ti_msp_dl_config.h"
// ================== 包含头文件 ====================
#include <type_traits>

namespace hal::details_adc
{
    // ==================随配置变动部分====================
    constexpr uint8_t DMA_CHAN_ID =DMA_CH1_CHAN_ID;
    // ==================随配置变动部分====================
    // 我在板子上能找到的ADC对应的通道
    // 0:1,2,5,3,7,6
    // 1:0,1,2,3,4,5,6,8
    //要的是存储器而非通道
    template<uint32_t ADC_BASE,uint32_t ADC_MEM>
    class adc_config{
        static inline bool flag;
    public:
        // 获取ADC硬件寄存器指针
        static ADC12_Regs *get_base()
        {
            return reinterpret_cast<ADC12_Regs *>(ADC_BASE);
        }
        static constexpr DL_ADC12_MEM_IDX get_mem()
        {
             switch (ADC_MEM)
            {
            case 0:  return DL_ADC12_MEM_IDX_0;
            case 1:  return DL_ADC12_MEM_IDX_1;
            case 2:  return DL_ADC12_MEM_IDX_2;
            case 3:  return DL_ADC12_MEM_IDX_3;
            case 4:  return DL_ADC12_MEM_IDX_4;
            case 5:  return DL_ADC12_MEM_IDX_5;
            case 6:  return DL_ADC12_MEM_IDX_6;
            case 7:  return DL_ADC12_MEM_IDX_7;
            default: return DL_ADC12_MEM_IDX_0;
            }
        }
        static void init_with_dma()
        {
            DL_ADC12_ClockConfig gADC_0ClockConfig = {
                .clockSel       = DL_ADC12_CLOCK_ULPCLK,
                .divideRatio    = DL_ADC12_CLOCK_DIVIDE_16,
                .freqRange      = DL_ADC12_CLOCK_FREQ_RANGE_32_TO_40,
            };
            DL_ADC12_setClockConfig(get_base(), (DL_ADC12_ClockConfig *) &gADC_0ClockConfig);
            DL_ADC12_initSingleSample(get_base(),
                DL_ADC12_REPEAT_MODE_ENABLED, DL_ADC12_SAMPLING_SOURCE_AUTO, DL_ADC12_TRIG_SRC_SOFTWARE,
                DL_ADC12_SAMP_CONV_RES_12_BIT, DL_ADC12_SAMP_CONV_DATA_FORMAT_UNSIGNED);
            DL_ADC12_configConversionMem(get_base(), get_mem(),
                DL_ADC12_INPUT_CHAN_0, DL_ADC12_REFERENCE_VOLTAGE_VDDA, DL_ADC12_SAMPLE_TIMER_SOURCE_SCOMP0, DL_ADC12_AVERAGING_MODE_DISABLED,
                DL_ADC12_BURN_OUT_SOURCE_DISABLED, DL_ADC12_TRIGGER_MODE_AUTO_NEXT, DL_ADC12_WINDOWS_COMP_MODE_DISABLED);
            DL_ADC12_setPowerDownMode(get_base(),DL_ADC12_POWER_DOWN_MODE_MANUAL);
            DL_ADC12_setSampleTime0(get_base(),3);
            DL_ADC12_enableDMA(get_base());
            DL_ADC12_setDMASamplesCnt(get_base(),1);
            DL_ADC12_enableDMATrigger(get_base(),(DL_ADC12_DMA_MEM0_RESULT_LOADED));
            /* Enable ADC12 interrupt */
            DL_ADC12_clearInterruptStatus(get_base(),(DL_ADC12_INTERRUPT_DMA_DONE));
            DL_ADC12_enableInterrupt(get_base(),(DL_ADC12_INTERRUPT_DMA_DONE));
            DL_ADC12_enableConversions(get_base());
            DL_DMA_Config gDMA_CH1Config = {
                .transferMode   = DL_DMA_FULL_CH_REPEAT_SINGLE_TRANSFER_MODE,
                .extendedMode   = DL_DMA_NORMAL_MODE,
                .destIncrement  = DL_DMA_ADDR_INCREMENT,
                .srcIncrement   = DL_DMA_ADDR_UNCHANGED,
                .destWidth      = DL_DMA_WIDTH_HALF_WORD,
                .srcWidth       = DL_DMA_WIDTH_HALF_WORD,
                .trigger        = DMA_ADC0_EVT_GEN_BD_TRIG,
                .triggerType    = DL_DMA_TRIGGER_TYPE_EXTERNAL,
            };
            //按照数组大小更改
            DL_DMA_setTransferSize(DMA, DMA_CHAN_ID, 1000);
            DL_DMA_initChannel(DMA, DMA_CHAN_ID , (DL_DMA_Config *) &gDMA_CH1Config);
        }
        static void init_with_dma_fifo()
        {
            /* ADC_0 Initialization */
            DL_ADC12_ClockConfig gADC_0ClockConfig = {
                .clockSel = DL_ADC12_CLOCK_ULPCLK,
                .divideRatio = DL_ADC12_CLOCK_DIVIDE_16,
                .freqRange = DL_ADC12_CLOCK_FREQ_RANGE_32_TO_40,
            };
            DL_ADC12_setClockConfig(get_base(), (DL_ADC12_ClockConfig*)&gADC_0ClockConfig);
            DL_ADC12_initSingleSample(get_base(),
                                      DL_ADC12_REPEAT_MODE_ENABLED, DL_ADC12_SAMPLING_SOURCE_AUTO,
                                      DL_ADC12_TRIG_SRC_SOFTWARE,
                                      DL_ADC12_SAMP_CONV_RES_12_BIT, DL_ADC12_SAMP_CONV_DATA_FORMAT_UNSIGNED);
            DL_ADC12_configConversionMem(get_base(), get_mem(),
                                         DL_ADC12_INPUT_CHAN_0, DL_ADC12_REFERENCE_VOLTAGE_VDDA,
                                         DL_ADC12_SAMPLE_TIMER_SOURCE_SCOMP0, DL_ADC12_AVERAGING_MODE_DISABLED,
                                         DL_ADC12_BURN_OUT_SOURCE_DISABLED, DL_ADC12_TRIGGER_MODE_AUTO_NEXT,
                                         DL_ADC12_WINDOWS_COMP_MODE_DISABLED);
            DL_ADC12_enableFIFO(get_base());
            DL_ADC12_setPowerDownMode(get_base(),DL_ADC12_POWER_DOWN_MODE_MANUAL);
            DL_ADC12_setSampleTime0(get_base(), 3);
            DL_ADC12_enableDMA(get_base());
            DL_ADC12_setDMASamplesCnt(get_base(), 6);
            DL_ADC12_enableDMATrigger(get_base(), (DL_ADC12_DMA_MEM11_RESULT_LOADED));
            /* Enable ADC12 interrupt */
            DL_ADC12_clearInterruptStatus(get_base(), (DL_ADC12_INTERRUPT_DMA_DONE));
            DL_ADC12_enableInterrupt(get_base(), (DL_ADC12_INTERRUPT_DMA_DONE));
            DL_ADC12_enableConversions(get_base());

            DL_DMA_Config gDMA_CH1Config = {
                .transferMode = DL_DMA_FULL_CH_REPEAT_SINGLE_TRANSFER_MODE,
                .extendedMode = DL_DMA_NORMAL_MODE,
                .destIncrement = DL_DMA_ADDR_INCREMENT,
                .srcIncrement = DL_DMA_ADDR_UNCHANGED,
                .destWidth = DL_DMA_WIDTH_WORD,
                .srcWidth = DL_DMA_WIDTH_WORD,
                .trigger = DMA_ADC0_EVT_GEN_BD_TRIG,
                .triggerType = DL_DMA_TRIGGER_TYPE_EXTERNAL,
            };
            //按照数组大小更改（数组大小的一半）
            DL_DMA_setTransferSize(DMA, DMA_CHAN_ID, 500);
            DL_DMA_initChannel(DMA, DMA_CHAN_ID, (DL_DMA_Config*)&gDMA_CH1Config);
        }
        // 获取adc中断
        static constexpr IRQn_Type get_isr()
        {
            if constexpr (ADC_BASE == ADC0_BASE)
                return ADC0_INT_IRQn;
            else if constexpr (ADC_BASE == ADC1_BASE)
                return ADC1_INT_IRQn;
            return ADC0_INT_IRQn;
        }

        // 获取的adc mem寄存器的地址
        static constexpr uint32_t get_src_addr()
        {
            if constexpr (ADC_BASE == ADC0_BASE || ADC_BASE == ADC1_BASE)
                switch (ADC_MEM)
                {
                case 0: return 0x40556280;
                case 1: return 0x40556284;
                case 2: return 0x40556288;
                case 3: return 0x4055628C;
                case 4: return 0x40556290;
                case 5: return 0x40556294;
                case 6: return 0x40556298;
                case 7: return 0x4055629C;
                case 8: return 0x405562A0;
                case 9: return 0x405562A4;
                case 10: return 0x405562A8;
                case 11: return 0x405562AC;
                default: return 0x40556280;
                }
            return 0x40556280;
        }

        // repeat模式详解：adc转换需要两个标志 enable和start分别控制这两个标志，enable在初始化中已经调用过一次，start需手动调
        static void adc_start()
        {
            DL_ADC12_startConversion(get_base());
        }

        /**
         * @note 一定要adc_reset才能重启
         */
        static void adc_diable()
        {
            DL_ADC12_disableConversions(get_base());
        }
        static void adc_reset()
        {
            DL_ADC12_enableConversions(get_base());
            DL_ADC12_startConversion(get_base());
        }
        static unsigned int adc_getValue()
        {
            unsigned int gAdcResult = 0;

            //使能ADC转换
            DL_ADC12_enableConversions(get_base());
            //软件触发ADC开始转换
            DL_ADC12_startConversion(get_base());

            //如果当前状态 不是 空闲状态
            while (DL_ADC12_getStatus(get_base()) != DL_ADC12_STATUS_CONVERSION_IDLE) {}

            //清除触发转换状态
            DL_ADC12_stopConversion(get_base());
            //失能ADC转换
            DL_ADC12_disableConversions(get_base());

            //获取数据
            gAdcResult = DL_ADC12_getMemResult(get_base(), get_mem());

            return gAdcResult;
        }
        /**
         * @brief 直接开始带dma的adc传输
         */
        static inline void start_adc_dma(uint32_t dst_addr)
        {
            DL_DMA_setSrcAddr(DMA, DMA_CHAN_ID,get_src_addr());

            DL_DMA_setDestAddr(DMA, DMA_CHAN_ID, dst_addr);
            //初始化里一次DMA传输大小没设置再设置
            // DL_DMA_setTransferSize(DMA, DMA_CH0_CHAN_ID, 1000);
            DL_DMA_enableChannel(DMA, DMA_CHAN_ID);
            /* Setup interrupts on device */
            NVIC_EnableIRQ(get_isr());
            DL_ADC12_startConversion(get_base());
        }
                /**
         * @brief 直接开始带dma的adc传输
         */
        static inline void start_adc_dma_fifo(uint32_t dst_addr)
        {
            DL_DMA_setSrcAddr(DMA, DMA_CHAN_ID,DL_ADC12_getFIFOAddress(get_base()));

            DL_DMA_setDestAddr(DMA, DMA_CHAN_ID,dst_addr );
            //初始化里一次DMA传输大小没设置再设置
            // DL_DMA_setTransferSize(DMA, DMA_CH0_CHAN_ID, 1000);
            DL_DMA_enableChannel(DMA, DMA_CHAN_ID);
            /* Setup interrupts on device */
            NVIC_EnableIRQ(get_isr());
            DL_ADC12_startConversion(get_base());
        }
    };


} // namespace hal::details_spi

namespace hal
{
    /**
     * @brief 模版类中 要的是存储的寄存器MEN而不是通道！！！
     */
    using adc0_0 = details_adc::adc_config<ADC0_BASE,0>;
    using adc0_1 = details_adc::adc_config<ADC0_BASE,1>;
    using adc0_2 = details_adc::adc_config<ADC0_BASE,2>;
    using adc0_3 = details_adc::adc_config<ADC0_BASE,3>;
    using adc0_4 = details_adc::adc_config<ADC0_BASE,4>;
    using adc0_5 = details_adc::adc_config<ADC0_BASE,5>;
    using adc0_6 = details_adc::adc_config<ADC0_BASE,6>;
    using adc0_7 = details_adc::adc_config<ADC0_BASE,7>;
    using adc0_8 = details_adc::adc_config<ADC0_BASE,8>;

    using adc1_0 = details_adc::adc_config<ADC1_BASE,1>;
    using adc1_1 = details_adc::adc_config<ADC1_BASE,1>;
    using adc1_2 = details_adc::adc_config<ADC1_BASE,2>;
    using adc1_3 = details_adc::adc_config<ADC1_BASE,3>;
    using adc1_4 = details_adc::adc_config<ADC1_BASE,4>;
    using adc1_5 = details_adc::adc_config<ADC1_BASE,5>;
    using adc1_6 = details_adc::adc_config<ADC1_BASE,6>;
    using adc1_7 = details_adc::adc_config<ADC1_BASE,7>;
    using adc1_8 = details_adc::adc_config<ADC1_BASE,8>;

}



